﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;
using System.ComponentModel;
using System.Threading;
using System.Windows.Media;

namespace MIBETerminal
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        SerialPortService serialPortService;
        private BackgroundWorker _backgroundWorker;
        private ManualResetEvent newDataEvent;
        public bool backgroundThreadContinue { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            serialPortService = new SerialPortService();

            newDataEvent = new ManualResetEvent(false);
            serialPortService.NewData = newDataEvent ;

            InitializeBackgroundWorker();

            portNameComboBox.ItemsSource = SerialPort.GetPortNames();
            baudrateComboBox.ItemsSource = SerialPortService.GetBaudrates();
            parityComboBox.ItemsSource = SerialPortService.GetParity();

            terminalOutputTextBox.UndoLimit = 0;
            DataContext = new MainWindowViewModel();

            serialPortService.NewDataDelegate += new EventHandler(serialPortService_NewDataDelegate);
        }

        void serialPortService_NewDataDelegate(object sender, EventArgs e)
        {
            //assume that we have in EventArgs copy of all logs;
            //then we can just:
            terminalOutputTextBox.Dispatcher.Invoke(new updateTerminalOutput(anotherTerminalOutputHelperMethod), e);
        }

        private void InitializeBackgroundWorker()
        {
            backgroundThreadContinue = true;
            _backgroundWorker = new BackgroundWorker();
            _backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
            _backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
            _backgroundWorker.WorkerSupportsCancellation = true;
            _backgroundWorker.WorkerReportsProgress = true;
        }

        void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Console.WriteLine("PROGRESS REPORT!!!!!!!!!!!");
            List<string> logi = serialPortService.getCopyOfLogBuffer();
            terminalOutputTextBox.Document.Blocks.Clear();
            logi.ForEach(logLine =>
                {
                    TextPointer tp = terminalOutputTextBox.Document.ContentEnd;
                    TextRange tr = new TextRange(tp,tp);
                    //tr.ApplyPropertyValue(TextElement.ForegroundProperty, Color.Red);
                    terminalOutputTextBox.AppendText(logLine + "\n");
                });

            terminalOutputTextBox.ScrollToEnd();
            //List<FilteredLog> filteredLogs = serialPortService.getFilteredLogs();
            //List<string> rawLogText = filteredLogs.ConvertAll(filteredLog => filteredLog.logText);
            //rawLogText.ForEach(logLine => terminalOutputTextBox.Text += ( logLine + "\n" ));
            //terminalOutputTextBox.Text += tmp;
        }

        void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (backgroundThreadContinue)
            {
                newDataEvent.WaitOne();
                newDataEvent.Reset();
                _backgroundWorker.ReportProgress(0);
            }
        }

        private void connectButton_Click(object sender, RoutedEventArgs e)
        {
            TextPointer tp = terminalOutputTextBox.Document.ContentEnd;
            TextRange tr = new TextRange(tp, tp);
            tr.Text = "DUPAAAAAA";
            tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
            toggleConnectButton();
            //_backgroundWorker.RunWorkerAsync();
        }

        private void toggleConnectButton()
        {
            string currentButtonName = (string)connectButton.Content;
            string connectWord = "Connect";

            //TODO: should not rely only on button state. Or can I?
            if (currentButtonName.Equals(connectWord)) 
            {
                connectButton.Content = "Disconnect";
                serialPortService.setupSerialPort(BuildSerialPortParameters());
                //serialPortService.Connect();
            }
            else
            {
                connectButton.Content = "Connect";
                //serialPortService.Disconnect();
            }
        }

        private SerialPortParameters BuildSerialPortParameters()
        {
            SerialPortParameters serialPortParameters = new SerialPortParameters();
            serialPortParameters.PortName = portNameComboBox.Text;
            serialPortParameters.BaudRate(baudrateComboBox.Text);
            serialPortParameters.Parity(parityComboBox.Text);
            return serialPortParameters;
        }

        public void testingMethod()
        {
            dataGrid1.Items.Add("John");
            dataGrid1.Items.Add("Jill");

            dataGrid1.Columns.Add(new DataGridTextColumn());

            ((DataGridTextColumn)dataGrid1.Columns[0]).Binding = new Binding(".");
            ((DataGridTextColumn)dataGrid1.Columns[0]).Header = "Name";

            DataGridTextColumn col1 = new DataGridTextColumn();
            col1.Header = "Second";
            dataGrid1.Columns.Add(col1);
            //col1.Binding = new Binding(".");
        }

        private void terminalInput_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                terminalOutputTextBox.AppendText("You Entered: " + terminalInput.Text);
                //only if connected
                //serialPortService.WriteLine(terminalInput.Text + "\n");
                terminalInput.Clear();
            }
        }

        private void QuitItem_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        public void anotherTerminalOutputHelperMethod(EventArgs e)
        {
        }

        public delegate void updateTerminalOutput(EventArgs e);
    }
}
